#ifndef DATACELL_H_
#define DATACELL_H_

#include "scHeader.h"
#include <VarC.h>
#include <QString>
#include <QDateTime>

namespace std
{
ostream& operator<<(ostream& out, const ::QString & q);
ostream& operator<<(ostream& out, const ::QDateTime & q);
}


namespace sybilpm
{
class DataCell : public dwkUtil::VarC
{
public:
	using VarC::operator=; // so you can use the assignments of the base class
	enum Type
	{
		TY_NONE = 0,	// copy from base class...
		TY_BOOL,
		TY_INT,
		TY_DOUBLE,
		TY_STRING,
		TY_DYNENUM,
		TY_RES1,
		TY_RES2,
		TY_RES3,
		// added types
		TY_DBKEY,		// database key as qint64
		TY_QSTRING,		// Qt's QString
		TY_QDATETIME	// Qt's QDateTime
		//TY_DURATION		// an "amount" of time
	};

	// these are the minimum required ctor's
	DataCell(Type type);
	DataCell(const DataCell & that);
	DataCell(Type type, const char * id);
	virtual ~DataCell();
	DataCell & operator=(const DataCell & that);
	DataCell(const PkType & data, const char * id, const char * visibleName, const char * unit);
	DataCell(const QString & data, const char * id, const char * visibleName, const char * unit);
	DataCell(const QDateTime & data, const char * id, const char * visibleName, const char * unit);
	// forward to base
	DataCell(long data, const char * id, const char * visibleName, const char * unit) :
		VarC(data, id, visibleName, unit) {}

	// setter and getter for added type
	DataCell & operator=(const PkType & data)
	{
		verifyType((VarC::Type)TY_DBKEY);
		state=ST_DIRTY;
		*((PkType *)(d.dp))=data;
		return *this;
	}
	DataCell & operator=(const QString & data)
	{
		verifyType((VarC::Type)TY_QSTRING);
		state=ST_DIRTY;
		*((QString *)(d.dp))=data;
		return *this;
	}
	DataCell & operator=(const QDateTime & data)
	{
		verifyType((VarC::Type)TY_QDATETIME);
		state=ST_DIRTY;
		*((QDateTime *)(d.dp))=data;
		return *this;
	}
	bool operator==(const PkType & data) {if(!verifyType((VarC::Type)TY_DBKEY, true)) return false; return *((PkType *)(d.dp))==data;}
	bool operator==(const QString & data) {if(!verifyType((VarC::Type)TY_QSTRING, true)) return false; return *((QString *)(d.dp))==data;}
	bool operator==(const QDateTime & data) {if(!verifyType((VarC::Type)TY_QDATETIME, true)) return false; return *((QDateTime *)(d.dp))==data;}
	bool operator!=(const PkType & data) {if(!verifyType((VarC::Type)TY_DBKEY, true)) return true; return *((PkType *)(d.dp))!=data;}
	bool operator!=(const QString & data) {if(!verifyType((VarC::Type)TY_QSTRING, true)) return true; return *((QString *)(d.dp))!=data;}
	bool operator!=(const QDateTime & data) {if(!verifyType((VarC::Type)TY_QDATETIME, true)) return true; return *((QDateTime *)(d.dp))!=data;}

	/**
	 * Getter with hard type-checking. Will throw if applied to a DataCell
	 * not natively QString.
	 */
	const PkType & getDbKey() const
	{
		verifySet((VarC::Type)TY_DBKEY);
		return *((PkType*)(d.dp));
	}
	PkType & getDbKeyV()
	{
		verifyType((VarC::Type)TY_DBKEY);
		state=ST_DIRTY;
		return *((PkType*)(d.dp));
	}
	const QString & getQString() const
	{
		verifySet((VarC::Type)TY_QSTRING);
		return *((QString*)(d.dp));
	}
	QString & getQStringV()
	{
		verifyType((VarC::Type)TY_QSTRING);
		state=ST_DIRTY;
		return *((QString*)(d.dp));
	}
	const QDateTime & getQDateTime() const
	{
		verifySet((VarC::Type)TY_QDATETIME);
		return *((QDateTime*)(d.dp));
	}
	QDateTime & getQDateTimeV()
	{
		verifyType((VarC::Type)TY_QDATETIME);
		state=ST_DIRTY;
		return *((QDateTime*)(d.dp));
	}
	/**
	 * Converting getters. No matter what the underlying type is, these
	 * getters will try to convert and return a "best guess" result.
	 */
	long getAsInt() const;
	QString getAsQString(bool asUser) const;
	bool tryUpdate(QString data, bool asUser);

protected:
	void create(const DataCell * that);
	virtual void release();

private:
	DataCell(); // intentionally no implementation - hide the default ctor as in base
};
} // namespace sybilpm

namespace std
{
ostream& operator<<(ostream& out, const sybilpm::DataCell & var);
}

#endif /* DATACELL_H_ */
